package org.androbuzz;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;

public class AndroBuzzSAXHandler extends DefaultHandler {
	
	private boolean inFeed = false;	
    private boolean inEntry = false;   
    private boolean inAuthor = false;
    private boolean inAddress = false;
    private boolean inSource = false;
    private boolean inService = false;
    private boolean inObject = false;
    private boolean inAttachment = false;
	private boolean inNotHandled = false;
	
	private String notHandledName = new String();
    
    AndroBuzzSummaryCleaner cleaner = new AndroBuzzSummaryCleaner();
    
    public class Media {
    	public String url;
    	public String height;
    	public String width;
    	public String kind;
    	public String type;
    }
    
    public class Activity {
    	public String activityId;
    	public String author;
    	public String author_key;
    	public String author_photo_url;
    	public String date_published;
    	public String date_updated;
    	public String summary;
    	public String content;
    	public String nb_comments;
    	public String date_comments;
    	public String source;
    	public String geo_coord;
    	public String geo_name;
    	public String geo_address;
    	ArrayList <Media> mediaList = new ArrayList<Media>();
    } 
    
    public class Feed {
    	ArrayList <Activity> mActivityList = new ArrayList<Activity>();
    	public String feedId;
    	public String author_google_id_name;
    	public String author_google_id_key;   
    	public String nextLink;
    	public String kind;
    }
    
    private String currentReadValue = new String();
    
    private Activity curBuzz = null;
    
    private Feed mFeed = null;
    
    private Media curMedia = null;
    
	static public String parseAuthorURI(String author_uri)
	{
		if(author_uri != null)
		{
			int curIdx = author_uri.lastIndexOf('/');
			if(curIdx != -1 && author_uri.length() > curIdx + 1)
			{
				return author_uri.substring(curIdx + 1);
			}
			//Log.e("AndroBuzz SAX error", "Cannot parse uri: " + author_uri);
		}
		else
			Log.e("AndroBuzz SAX error", "Cannot parse uri because is null !");
		return "";
	}
	
	static public String parseGoogleIdLong(String google_id_long)
	{
		if(google_id_long != null)
		{
			google_id_long = google_id_long.replace("https://www.googleapis.com/buzz/v1/activities/", "");

			int curIdx = google_id_long.indexOf('/');
			if(curIdx != -1 && google_id_long.length() > curIdx + 1)
			{
				return google_id_long.substring(0, curIdx);
			}
			//Log.e("AndroBuzz SAX error", "Cannot parse google_id_long: " + google_id_long);
		}
		else
			Log.e("AndroBuzz SAX error", "Cannot parse google_id_long because is null !");
		return "";
	}
	
	static public boolean checkAuthorIdIsKey(String author_id)
	{
		try
		{
			Long.parseLong(author_id);
		}
		catch(NumberFormatException e)
		{
			return false;
		}
		return true;
	}
    
    /** 
     * Format date & time of a buzz to a nice and readable format
     */
    private String formatDateTime(String datetime) {
    	if(datetime.length() > 19)
    	{
    	Calendar calendar = new GregorianCalendar();
    	Date currentDate = new Date();
    	calendar.setTime(currentDate);
    	
    	//String currentYear = Integer.toString(calendar.get(Calendar.YEAR));
    	int currentMonthInt = calendar.get(Calendar.MONTH) + 1;
    	//String currentMonth = (currentMonthInt < 10) ? "0".concat(Integer.toString(currentMonthInt)) : Integer.toString(currentMonthInt);
    	int currentDayInt = calendar.get(Calendar.DATE);
    	//String currentDay = (currentDayInt < 10) ? "0".concat(Integer.toString(currentDayInt)) : Integer.toString(currentDayInt);
    	
    	String year = datetime.substring(0, 4);
    	String month = datetime.substring(5, 7);
    	String day = datetime.substring(8, 10);
    	String hour = datetime.substring(11, 13);
    	String minute = datetime.substring(14, 16);
    	
    	
    	//Message to quentin : datetime clean code should be in cursorAdapter
    	String seconde = datetime.substring(17, 19);
    	
    /*	if(year.equals(currentYear)) {
    		if(month.equals(currentMonth) && day.equals(currentDay)) {
				datetime = hour.concat(":").concat(minute);
    		}
    		else {
				datetime = day.concat("/").concat(month).concat(" ").concat(hour).concat(":").concat(minute);
			}
    	}
    	else {
    		datetime = day.concat("/").concat(month).concat("/").concat(year).concat(" ").concat(hour).concat(":").concat(minute);
    	}*/
    	
    	datetime = year.concat("/").concat(month).concat("/").concat(day).concat(" ").concat(hour).concat(":").concat(minute).concat(":").concat(seconde);
    	}
    	else
    		Log.e("AndroBuzz SAX error", "wrong datetime: " + datetime);
    	return datetime;
    }

    /** 
     * Called when opening tags i.e. <tag> 
     * Can provide attribute(s), i.e. <tag attribute="attributeValue">
     */
    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
    				throws SAXException {
    	currentReadValue = "";
    	
    	if(!inNotHandled)
    	{
	    	if(!inFeed)
	    	{
	        	if (localName.equals("feed")) {
	        		inFeed = true;
	        		mFeed = new Feed();
        			mFeed.kind = atts.getValue(atts.getURI(0),"kind");
	        	}
	        	else
	        	{
	        		inNotHandled = true;
	        		notHandledName = localName;
	        	}
	    	}
	    	else
	    	{
	    		if(!inEntry)
	    		{
	    			if(localName.contains("link") && atts.getValue("rel").contains("self") && atts.getValue("href").contains("https://www.googleapis.com/buzz/v1/activities/"))
	    	        {
	    	        	mFeed.author_google_id_key = parseGoogleIdLong(atts.getValue("href"));
	    	        } 	
	    			else if(localName.contains("link") && atts.getValue("rel").contains("next") && atts.getValue("href").contains("https://www.googleapis.com/buzz/v1/activities/"))
	    	        {
	    	        	mFeed.nextLink = atts.getValue("href");
	    	        } 	
	    			else if(localName.equals("entry"))
	    			{
	    				curBuzz = new Activity();
	    				inEntry = true;
	    			}
	    			else if(!localName.equals("id")	) 
					{
	            		inNotHandled = true;
	            		notHandledName = localName;
					}
	    		}
	    		else 
	    		{
	    			if(!inAuthor)
	    			{
	    				if(inAddress)
	    				{
	    					if(!localName.equals("formatted"))
	    					{
	    						inNotHandled = true;
			            		notHandledName = localName;	  
	    					}
	    				}
	    				else if(inSource)
	    				{
	    					if(inService)
	    					{
	    						if(!localName.equals("title"))
	    						{
	    		            		inNotHandled = true;
	    		            		notHandledName = localName;	 	    							
	    						}
	    					}
	    					else if(localName.equals("service"))
	    					{
	    						inService = true;
	    					}
	    					else
	    					{
			            		inNotHandled = true;
			            		notHandledName = localName;	 
	    					}
	    				}
	    				else if(inObject)
	    				{
	    					if(inAttachment)
	    					{
	    						if(!localName.equals("link"))
	    						{
	    		            		inNotHandled = true;
	    		            		notHandledName = localName;	 						
	    						}
	    						else						
	    						{
	    							curMedia = new Media();
	    							curMedia.url =  atts.getValue("href");
	    							curMedia.width = atts.getValue(atts.getURI(2),"width");
	    							curMedia.height = atts.getValue(atts.getURI(2),"height");
	    							curMedia.kind = atts.getValue("rel");
	    							curMedia.type = atts.getValue("type");
	    						}
	    					}
	    					else if(localName.equals("attachment"))
	    					{
	    						inAttachment = true;
	    					}
	    					else
	    					{
			            		inNotHandled = true;
			            		notHandledName = localName;	 				
	    					}
	    				}
	    				else if(localName.equals("author"))
		    			{
		    				inAuthor = true;
		    			}
		    			else if(localName.contains("link") && atts.getValue("rel").contains("replies"))
		    			{
		    				curBuzz.nb_comments = atts.getValue(2);
		    			}
		    			else if(localName.equals("address"))
		    			{
		    				inAddress = true;
		    			}
		    			else if(localName.equals("source"))
		    			{
		    				inSource = true;
		    			}
		    			else if(localName.equals("object"))
		    			{
		    				inObject = true;
		    			}
    					else if(!localName.equals("published") &&
		    					!localName.equals("updated") &&
		    					!localName.equals("content") &&
		    					!localName.equals("id") &&
		    					!localName.equals("point") &&
		    					!localName.equals("featureName"))
		    			{
		            		//Log.i("AndroBuzz SAX info", "not handled " + localName);
		            		inNotHandled = true;
		            		notHandledName = localName;	    				
		    			}
	    			}
	    			else
	    			{
	    				if(!localName.equals("name") &&
    						!localName.equals("uri") &&
    						!localName.equals("photoUrl"))
	    				{
	    	        		//Log.i("AndroBuzz SAX info", "not handled " + localName);
	    	        		inNotHandled = true;
	    	        		notHandledName = localName;	
	    				}
	    			}
	    		}
	    		
	    	}
    	}
    }

    /**
     * Called when closing tags i.e. </tag>
     */
    @Override
    public void endElement(String namespaceURI, String localName, String qName)
    				throws SAXException {
    	//Log.i("AndroBuzz SAX info", "endElement local " + localName + "   qName " + qName);
    	
    	if(inNotHandled)
    	{
    		if(notHandledName.equals(localName))
    		{
        		//Log.i("AndroBuzz SAX info", "not handled end of " + localName);
    			inNotHandled = false;
    			notHandledName = "";
    		}
    	}
    	else if(inFeed)
    	{
    		if(inEntry)
    		{
    			if(inAuthor)
    			{
    				if(localName.equals("name"))
    				{
    					curBuzz.author = currentReadValue;
    				}
    				else if(localName.equals("uri"))
    				{
    					String temp_author_google_id = parseAuthorURI(currentReadValue).toLowerCase();
    					if(!temp_author_google_id.equals(mFeed.author_google_id_name) && !temp_author_google_id.equals(mFeed.author_google_id_key) && !checkAuthorIdIsKey(temp_author_google_id))
    						mFeed.author_google_id_name = temp_author_google_id; 
    					curBuzz.author_key =  temp_author_google_id; 					
    				}
    				else if(localName.equals("photoUrl"))
    				{
    					curBuzz.author_photo_url = currentReadValue;
    				}
        			else if(localName.equals("author"))
        			{
        				inAuthor = false;
        			}
    			}
    			else if(inAddress)
    			{
    				if(localName.equals("formatted"))
    				{
    					curBuzz.geo_address = currentReadValue;
    				}
        			else if(localName.equals("address"))
        			{
        				inAddress = false;
        			}
    			}
    			else if(inSource)
    			{
    				if(inService)
    				{
    					if(localName.equals("title"))
    					{
    						curBuzz.source = currentReadValue;
    					}
        				else if(localName.equals("service"))
        				{
        					inService = false;
        				}
    				}
    				else if(localName.equals("source"))
    				{
    					inSource = false;
    				}
    			}
    			else if(inObject)
    			{
    				if(inAttachment)
    				{
    					if(localName.equals("link"))
    					{
    						curBuzz.mediaList.add(curMedia);
    						curMedia = null;
    					}
    					else if(localName.equals("attachment"))
        				{
        					inAttachment = false;
        				}
    				}
    				else if(localName.equals("object"))
    				{
    					inObject = false;
    				}
    			}
    			else if(localName.equals("published"))
    			{
    				curBuzz.date_published = currentReadValue;
    			}
    			else if(localName.equals("updated"))
    			{
    				curBuzz.date_updated = currentReadValue;
    			}
    			else if(localName.equals("id"))
    			{
    				curBuzz.activityId = currentReadValue;
    			}
    			else if(localName.equals("content"))
    			{
    				curBuzz.content = currentReadValue;
    				curBuzz.summary = cleaner.cleanSummary(currentReadValue, 80);
    			}
    			else if(localName.equals("point"))
    			{
    				curBuzz.geo_coord = currentReadValue;
    			}
    			else if(localName.equals("featureName"))
    			{
    				curBuzz.geo_name = currentReadValue;
    			}
    			else if(localName.equals("entry"))
    			{
    	    		inEntry = false;
    	    		mFeed.mActivityList.add(curBuzz);
    	    		curBuzz = null; 				
    			}
    		}
    		else if(localName.equals("id"))
    		{
				mFeed.feedId = currentReadValue;
    		}
    		else if(localName.equals("feed"))
    		{
    			inFeed = false;
    		}
    	}
    }

    /**
     * Called on the following structure : <tag>characters</tag>
     */
    @Override
    public void characters(char ch[], int start, int length) {

    	String chars = new String(ch, start, length);
    	
    	currentReadValue += chars;
    	//Log.i("AndroBuzz SAX info", "characters: " + chars);	
    }
    
    public Feed createBuzzReader(Context ctx, URL url) {
    	inFeed = false;	
        inEntry = false;   
        inAuthor = false;
        inAddress = false;
        inSource = false;
        inService = false;
        inObject = false;
        inAttachment = false;
    	inNotHandled = false;
    	notHandledName = "";
        curBuzz = null;
        curMedia = null;
        mFeed = null;

    	SAXParserFactory spf = SAXParserFactory.newInstance();
    	
		try {
			
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			xr.setContentHandler(this);
	        xr.parse(new InputSource(url.openStream()));
	        
		} catch (ParserConfigurationException e) {
			Log.e("AndroBuzz Parser Configuration Exception", e.toString());
			e.printStackTrace();
		} catch (SAXException e) {
			Log.e("AndroBuzz SAX Exception", e.toString() + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			Log.w("AndroBuzz I/O Exception", "Cannot get buzz feed " + e.toString());
			//e.printStackTrace();
		}
		
		return mFeed;
    }

}
